package com.common.aspect;

/**
 * @ClassName ValueRuleAspect
 * @Description TODO
 * @Author 无名小卒
 * @Date 2023/9/15 18:08
 * @Version 1.0
 */

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.support.reader.YamlRuleDefinitionReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.io.File;
import java.io.FileReader;
import java.util.*;

/**
 * 值规则校验
 */
@Aspect
@Component
public class ValueRuleAspect {
    @Value("${valueRule.file.outdir:D:\\MyProgram\\JavaProject\\fm-admin\\rules\\value-rule}")
    private String valueRuleoutDir;

    private static MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());

    /**
     * 切入mybatis-plus
     */
    @Pointcut("execution(* com.baomidou.mybatisplus.core.mapper.BaseMapper.*(..))")
    public void controllerPointcut() {
    }

    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        if (name.startsWith("insert") || name.startsWith("update")) {//插入和更新坐值校验
            Object[] args = joinPoint.getArgs();
            Class aClass = args[0].getClass();
            TableName annotation = (TableName) aClass.getAnnotation(TableName.class);
            BeanMap beanMap = BeanMap.create(args[0]);
            Map data = new HashMap();
            for (Object key : beanMap.keySet()) {
                if (name.startsWith("insert")) {
                    data.put(getTableField(aClass, key.toString()), beanMap.get(key));
                } else {
                    if (Objects.nonNull(beanMap.get(key))) {//字段属性为空忽略值校验
                        data.put(getTableField(aClass, key.toString()), beanMap.get(key));
                    }
                }
            }
            // define facts
            Facts facts = new Facts();
            facts.put("entity", data);
            facts.put("result", new HashMap<>());
            String value = annotation.value();
            File valueRuleFile = getValueRuleFile(String.format("%sValueRule.yml", value));
            if (Objects.nonNull(valueRuleFile)) {//如果配置了值规则文件
                Rule rule = ruleFactory.createRule(new FileReader(valueRuleFile));
                if (Objects.nonNull(rule)) {
                    Rules rules = new Rules();
                    rules.register(rule);
                    // fire rules on known facts
                    RulesEngine rulesEngine = new DefaultRulesEngine();
                    rulesEngine.fire(rules, facts);
                    Map result = facts.get("result");
                    Object resultdata = result.get("data");
                    if (!ObjectUtils.isEmpty(resultdata)) {
                        throw new RuntimeException(resultdata.toString());
                    }
                }
            }
        }
    }


    public String getTableField(Class entity, String field) {
        String conlmn = "";
        try {
            TableField annotation = entity.getDeclaredField(field).getAnnotation(TableField.class);

            if (Objects.nonNull(annotation)) {
                conlmn = annotation.value().replaceAll("`", "");
            } else {
                TableId tableId = entity.getDeclaredField(field).getAnnotation(TableId.class);
                if (Objects.nonNull(tableId)) {
                    conlmn = tableId.value().replaceAll("`", "");
                }
            }
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
        return conlmn;

    }

    public File getValueRuleFile(String filaname) {
        File dir = new File(valueRuleoutDir);
        File file = null;
        Queue<File> queue = new LinkedList();
        queue.offer(dir);
        if (dir.exists() && dir.isDirectory()) {
            while (!queue.isEmpty()) {
                File poll = queue.poll();
                if (poll.isFile()) {
                    if (poll.getName().equals(filaname)) {
                        file = poll;
                        break;
                    }
                } else {
                    File[] files = poll.listFiles();
                    for (int i = 0, len = files.length; i < len; i++) {
                        queue.offer(files[i]);
                    }
                }
            }
        } else {
            throw new RuntimeException("值规则文件目录配置错误");
        }
        return file;
    }

}
